配置ipv4 ipv6优先级
·
linux系统中的ip选择
在 Linux 系统中,默认情况下,许多应用(尤其是使用 glibc 的 getaddrinfo() 的程序,如 curl、wget、ssh 等)会遵循 RFC 6724 的地址选择策略,优先选择 IPv6(若 AAAA 记录存在且网络支持),即使 IPv4 可用。
要让系统/应用优先使用 IPv4,再回退到 IPv6,有以下几种常用方法(按推荐程度排序):
修改 gai.conf(全局、标准、推荐)
这是最标准、影响范围可控的方式,只影响使用 getaddrinfo() 的应用。
sudo vim /etc/gai.conf
# 优先 IPv4(将 ::ffff:0:0/96 的优先级调高)
# precedence ::ffff:0:0/96 100
sudo sed -i 's/#precedence ::ffff:0:0\/96 10/precedence ::ffff:0:0\/96 100/' /etc/gai.conf
原理:::ffff:0:0/96 是 IPv4-mapped IPv6 地址(如 ::ffff:192.0.2.1)。提高其优先级后,当域名同时有 A 和 AAAA 记录时,getaddrinfo() 会优先返回 IPv4 地址。
# 无需重启,新进程立即生效。
getent ahostsv4 example.com | head -1 # 应返回 IPv4
getent ahostsv6 example.com | head -1 # 应返回 IPv6
# 测试解析顺序(注意顺序):
python3 -c "import socket; print(socket.getaddrinfo('example.com', 80, socket.AF_UNSPEC, socket.SOCK_STREAM))"
环境变量(用户级/临时)
适用于特定用户或会话,不影响系统全局:
export GAI_CONF=/dev/null # 禁用 gai.conf(回退到旧行为,常优先 IPv4)
# 或更精准:
export GAI_CONF=<(echo "precedence ::ffff:0:0/96 100")
修改内核地址选择策略(推荐,行为最接近“IPv4 first”)
Linux 使用 RFC 3484 / RFC 6724 地址选择规则,可以通过 ip addrlabel 调整优先级,让 IPv4 地址的地址标签优先级更高。
- ➤ 查看当前地址标签:
ip addrlabel list
# 通常看到:
# prefix ::ffff:0.0.0.0/96 label 4
# prefix ::/0 label 1
其中 ::ffff:0.0.0.0/96 是 IPv4-mapped IPv6 地址。
- ➤ 让 IPv4-mapped 更优先:
sudo ip addrlabel add prefix ::ffff:0.0.0.0/96 label 0
# 让它的 label 更小 → 优先级更高。
- ➤ 或者反过来降低 IPv6 的优先级:
sudo ip addrlabel add prefix ::/0 label 10
不推荐的方法(副作用大)
- 禁用 IPv6(如 sysctl net.ipv6.conf.all.disable_ipv6=1):
- 虽可强制走 IPv4,但破坏 IPv6 功能,不符合现代网络趋势,且某些服务依赖 IPv6 localhost(如部分 Docker/LXC 配置),可能导致意外故障。
- 修改 /etc/hosts:
- 手动将域名映射到 IPv4 地址仅对特定主机名有效,不具普适性。
addrlable.conf 和gai.conf 的区别
/etc/iproute2/addrlabel.conf 和 /etc/gai.conf 都涉及 IP 地址优先级/排序,但它们的工作层级、目标、机制截然不同。下面我们从原理、作用域、典型场景三方面对比:
| 维度 | /etc/gai.conf | /etc/iproute2/addrlabel.conf |
|---|---|---|
| 标准依据 | RFC 6724 | RFC 6724 §2.1 + Linux 内核实现 |
| 作用对象 | ✅ 用户空间应用(通过 getaddrinfo()): curl, wget, ssh, python socket, systemd-resolved 等 | ✅ 内核空间(net/ipv6/addrlabel.c): 影响 内核生成的源地址标签(label),供 getaddrinfo() 读取参考 |
| 控制什么 | 应用层 地址排序规则(getaddrinfo() 的输出顺序) | 内核为每个 IPv6 地址分配的 label 值(ip addrlabel list 可见),是 gai.conf 中 label 规则的数据源 |
| 是否必须配合使用 | ❌ 可独立工作(可仅靠 precedence 规则) | ⚠️ 通常需配合 gai.conf 的 label 规则才生效;单独修改它不直接改变应用行为 |
| 典型配置项 | precedence, label, scopev4 | prefix label(如 ::1/128 0) |
| 生效方式 | 应用启动时读取(或按 GAI_CONF 环境变量) | ip addrlabel 加载;内核维护 label 表;getaddrinfo() 查询该表 |